#pragma once

#include "Component.h"

#include "ComponentRealization.h"
#include "Interface.h"
#include "PackageableElement.h"

namespace uml {

const bool Component::isIndirectlyInstantiated_default_ = true;
Component::Component(const QString& umlType)
    : Class(umlType) {}

void Component::fromJson(const QJsonObject& json, QStringList& errorList) {
    if (json.isEmpty()) {
        return;
    }

    Class::fromJson(json, errorList);
    isIndirectlyInstantiated_ = json.value("isIndirectlyInstantiated").toBool(isIndirectlyInstantiated_default_);
    JsonSerializable::fromJsonArray(packagedElements_, "packagedElements", json, errorList);
    JsonSerializable::fromJsonArray(provided_, "provided", json, errorList);
    JsonSerializable::fromJsonArray(realizations_, "realizations", json, errorList);
    JsonSerializable::fromJsonArray(required_, "required", json, errorList);
}

void Component::toJson(QJsonObject& json) {
    Class::toJson(json);
    if (isIndirectlyInstantiated_ != isIndirectlyInstantiated_default_) {
        json.insert("isIndirectlyInstantiated", isIndirectlyInstantiated_);
    }
    JsonSerializable::toJsonArray(packagedElements_, "packagedElements", json);
    JsonSerializable::toJsonArray(provided_, "provided", json);
    JsonSerializable::toJsonArray(realizations_, "realizations", json);
    JsonSerializable::toJsonArray(required_, "required", json);
}

/// <summary>
/// isIndirectlyInstantiated getter
/// If true, the Component is defined at design-time, but at run-time (or
/// execution-time) an object specified by the Component does not exist, that is,
/// the Component is instantiated indirectly, through the instantiation of its
/// realizing Classifiers or parts.
/// </summary>
bool Component::isIndirectlyInstantiated() const {
    return isIndirectlyInstantiated_;
}

/// <summary>
/// isIndirectlyInstantiated setter
/// If true, the Component is defined at design-time, but at run-time (or
/// execution-time) an object specified by the Component does not exist, that is,
/// the Component is instantiated indirectly, through the instantiation of its
/// realizing Classifiers or parts.
/// </summary>
void Component::setIsIndirectlyInstantiated(bool value) {
    isIndirectlyInstantiated_ = value;
}

/// <summary>
/// packagedElements getter
/// The set of PackageableElements that a Component owns. In the namespace of a
/// Component, all model elements that are involved in or related to its definition
/// may be owned or imported explicitly. These may include e.g., Classes,
/// Interfaces, Components, Packages, UseCases, Dependencies (e.g., mappings), and
/// Artifacts.
/// </summary>
vector<shared_ptr<PackageableElement>>& Component::packagedElements() {
    return packagedElements_;
}

/// <summary>
/// provided getter
/// The Interfaces that the Component exposes to its environment. These Interfaces
/// may be Realized by the Component or any of its realizingClassifiers, or they may
/// be the Interfaces that are provided by its public Ports.
/// </summary>
vector<shared_ptr<Interface>>& Component::provided() {
    return provided_;
}

/// <summary>
/// realizations getter
/// The set of Realizations owned by the Component. Realizations reference the
/// Classifiers of which the Component is an abstraction; i.e., that realize its
/// behavior.
/// </summary>
vector<shared_ptr<ComponentRealization>>& Component::realizations() {
    return realizations_;
}

/// <summary>
/// required getter
/// The Interfaces that the Component requires from other Components in its
/// environment in order to be able to offer its full set of provided functionality.
/// These Interfaces may be used by the Component or any of its
/// realizingClassifiers, or they may be the Interfaces that are required by its
/// public Ports.
/// </summary>
vector<shared_ptr<Interface>>& Component::required() {
    return required_;
}

} // namespace uml
